#include <queue>
#include <pthread.h>

using namespace std;

template<class T>
class BlockQueue 
{
    static const int defaultnum = 5;
public:
    BlockQueue(int maxcap = defaultnum) 
        : _maxcap(maxcap)
        , _mutex(PTHREAD_MUTEX_INITIALIZER)
        , _Pcond(PTHREAD_COND_INITIALIZER)
        , _Ccond(PTHREAD_COND_INITIALIZER)
    {}

    const T pop()
    {
        pthread_mutex_lock(&_mutex);
        while (_q.empty())
            pthread_cond_wait(&_Ccond, &_mutex);
        
        T ret = _q.front();
        _q.pop();

        pthread_cond_signal(&_Pcond);   //消费了之后，阻塞队列一定没满，可以唤醒生产信号量
        pthread_mutex_unlock(&_mutex);
        return ret;

    }

    void push(const T& in)
    {
        pthread_mutex_lock(&_mutex);
        while (_q.size() == _maxcap)        //防止伪唤醒
            pthread_cond_wait(&_Pcond, &_mutex);
        
        //1.队列本来就没满  2.队列满了，但是消费之后，被唤醒了
        _q.push(in);
        pthread_cond_signal(&_Ccond);   //生产了之后，阻塞队列一定有数据，可以唤醒消费信号量
        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue() 
    {}

private:
    queue<T> _q;     //阻塞队列（共享资源）
    int _maxcap;            //最大容量,最小为0
    pthread_mutex_t _mutex;         //生产和消费只能进行一个，所以只能公用一把锁
    pthread_cond_t _Pcond;      //生产和消费有独自的等待队列，所以需要两个条件变量
    pthread_cond_t _Ccond;
};
